package com.dbms.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dbms.domain.dto.BisXnjmodeProjectDTO;
import com.dbms.domain.entity.*;
import com.dbms.domain.vo.BisXnjmodeProjectVO;
import com.dbms.domain.vo.DataObject;
import com.dbms.domain.vo.QueryByIdForResultVO;
import com.dbms.enums.ProjectEnum;
import com.dbms.enums.SettingEnum;
import com.dbms.mapper.*;
import com.dbms.service.*;
import com.dbms.utils.DateIntervalCalculator;
import com.dbms.utils.HttpUtils;
import com.dbms.utils.SnowflakeIdGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class BisXnjmodeProjectServiceImpl implements BisXnjmodeProjectService {

    final BisXnjmodeProjectMapper mapper;
    final FloodmapSiteMapper floodmapSiteMapper;
    final FloodmapStationPropagateMapper floodmapStationPropagateMapper;
    final SnowflakeIdGenerator snowflakeIdGenerator;
    final BisXajmodeParasService bisXajmodeParasService;
    final BisModelPsparmsService bisModelPsparmsService;
    final BisXajmodelArearateService bisXajmodelArearateService;
    final StPptnRMService stPptnRMService;
    final StRiverRService stRiverRService;
    final BisReferencedDataService bisReferencedDataService;

    @Value("${call.back.url}")
    String callBackUrl;

    @Value("${big.model.url}")
    String bigModelUrl;

    @Override
    public boolean save(BisXnjmodeProjectDTO dto) {
            BisXnjmodeProject project = new BisXnjmodeProject();
            BeanUtils.copyProperties(dto,project);
            project.setPstartTime(DateIntervalCalculator.stringToDate(dto.getPstartTime()));
            project.setPendTime(DateIntervalCalculator.stringToDate(dto.getPendTime()));
            project.setId(dto.getRcId()+dto.getStcdId()+System.currentTimeMillis());
            project.setCreateDate(new Date());
            project.setIsType(dto.getType());
            // 河流ID(编码)
            FloodmapSite site = floodmapSiteMapper.selectById(dto.getRcId());
            project.setRcode(site.getCode());
            // 控制点
            FloodmapStationPropagate propagate = floodmapStationPropagateMapper.selectOne(new LambdaQueryWrapper<FloodmapStationPropagate>().eq(FloodmapStationPropagate::getStationCode,dto.getStcdId()));
            if(propagate == null){
                throw new RuntimeException("控制点为空");
            }
            project.setStcdR(propagate.getStationCode());
            // 输入参数JSON
            // BisXajmodeParas  BisXnjmodeProject BisModelPsparms BisXajmodelArearate
            BisXajmodeParas bisXajmodeParas = bisXajmodeParasService.getInfoByStationCode2(propagate.getStationCode());
            if(ObjectUtils.isEmpty(bisXajmodeParas)){
                throw new RuntimeException("模型参数缺省");
            }
            BisModelPsparms bisModelPsparms = bisModelPsparmsService.queryInfo();
            if(ObjectUtils.isEmpty(bisModelPsparms)){
                throw new RuntimeException("粒子参数缺省");
            }
            List<BisXajmodelArearate> bisXajmodelArearate = bisXajmodelArearateService.queryByStcdR(propagate.getStationCode());
            if(ObjectUtils.isEmpty(bisXajmodelArearate)){
                throw new RuntimeException("面积参数缺省");
            }

            JSONObject jsonObject = convertJson(bisXajmodeParas,project,bisModelPsparms,bisXajmodelArearate,dto.getType(),dto.getDataObjectList());
            project.setParms(jsonObject.toString());
            project.setStatus(ProjectEnum.编制完成.getCode());
            mapper.insert(project);
        return Boolean.TRUE;
    }

    @Override
    public boolean deleteByIds(List<String> ids) {
        mapper.deleteBatchIds(ids);
        return Boolean.TRUE;
    }

    @Override
    public boolean stop(String id) {
        BisXnjmodeProject project = mapper.selectById(id);
        project.setStatus(ProjectEnum.终止.getCode());
        mapper.updateById(project);
        return Boolean.TRUE;
    }

    @Override
    public boolean lvding(String id) throws IOException {
        BisXnjmodeProject project = mapper.selectById(id);
        if(project.getSetting() != null){
            if(project.getSetting().equals(SettingEnum.计算.getCode())){
                throw new RuntimeException("该记录只能执行计算");
            }
        }
        project.setStatus(ProjectEnum.运行中.getCode());
        project.setRstartTime(new Date());
        // 远程调用大模型接口
        JSONObject jsonObject = JSONObject.parseObject(project.getParms());
        jsonObject.put("model","1");
        System.out.println("大模型请求参数:"+jsonObject.toJSONString());
        HttpUtils.sendPostRequestWithJSON(bigModelUrl,jsonObject);
        project.setSetting(SettingEnum.率定.getCode());
        mapper.updateById(project);
        return Boolean.TRUE;
    }

    @Override
    public boolean count(String id) throws IOException {
        BisXnjmodeProject project = mapper.selectById(id);
        if(project.getSetting() != null){
            if(project.getSetting().equals(SettingEnum.率定.getCode())){
                throw new RuntimeException("该记录只能执行率定");
            }
        }
        project.setStatus(ProjectEnum.运行中.getCode());
        project.setRstartTime(new Date());
        // 远程调用大模型接口
        JSONObject jsonObject = JSONObject.parseObject(project.getParms());
        jsonObject.put("model","2");
        System.out.println("大模型请求参数:"+jsonObject.toJSONString());
        HttpUtils.sendPostRequestWithJSON(bigModelUrl,jsonObject);
        project.setSetting(SettingEnum.计算.getCode());
        mapper.updateById(project);
        return Boolean.TRUE;
    }

    @Override
    public List<BisXnjmodeProjectVO> querByList(String strcR,Integer type) {
        List<BisXnjmodeProject> list = mapper.selectList(new LambdaQueryWrapper<BisXnjmodeProject>()
                .eq(BisXnjmodeProject::getStcdR,strcR)
                .eq(BisXnjmodeProject::getIsType,type)
        );
        List<BisXnjmodeProjectVO> result = new ArrayList<>(list.size());
        for (BisXnjmodeProject project : list) {
            BisXnjmodeProjectVO vo = new BisXnjmodeProjectVO();
            BeanUtils.copyProperties(project,vo);
            FloodmapStationPropagate propagate = floodmapStationPropagateMapper.selectOne(new LambdaQueryWrapper<FloodmapStationPropagate>()
                    .eq(FloodmapStationPropagate::getStationCode,vo.getStcdR())
            );
            if(ObjectUtils.isNotEmpty(propagate)){
                vo.setStcdR(propagate.getStationName());
            }
            result.add(vo);
        }
        return result;
    }

    @Override
    public BisXnjmodeProject querById(String id) {
        return mapper.selectById(id);
    }

    @Override
    public boolean update(BisXnjmodeProject project) {
        mapper.updateById(project);
        return Boolean.TRUE;
    }

    @Override
    public List<QueryByIdForResultVO> queryByIdForResult(String id) {
        BisXnjmodeProject project = mapper.selectById(id);
        if(ObjectUtils.isEmpty(project)){
            throw new RuntimeException("project为空");
        }
        String result = project.getResult();
        JSONObject resultJson = JSONObject.parseObject(result);
        if(resultJson != null) {
            List<QueryByIdForResultVO> list = JSONArray.parseArray(resultJson.getString("result"), QueryByIdForResultVO.class);
            return list;
        }else{
            return null;
        }
    }


    public JSONObject convertJson(BisXajmodeParas paras, BisXnjmodeProject project, BisModelPsparms bisModelPsparms, List<BisXajmodelArearate> bisXajmodelArearate, Integer type, List<DataObject> dataObjectList){
        JSONObject jsonObject = new JSONObject();
        //
        jsonObject.put("id",project.getId());
        jsonObject.put("name", project.getPname());
        jsonObject.put("start-time", project.getPstartTime());
        jsonObject.put("end-time", project.getPendTime());
        jsonObject.put("callback",callBackUrl);
        jsonObject.put("step-len","60");
        jsonObject.put("model",type);

        JSONObject xajpara = new JSONObject();
        JSONObject zsfxxs = new JSONObject();
        zsfxxs.put("max",paras.getZsfxxsM());
        zsfxxs.put("min",paras.getZsfxxsS());
        zsfxxs.put("rate",paras.getZsfxxs());
        xajpara.put("zsfxxs",zsfxxs);

        JSONObject zysrl = new JSONObject();
        zysrl.put("max",paras.getZysrlM());
        zysrl.put("min",paras.getZysrlS());
        zysrl.put("rate",paras.getZysrl());
        xajpara.put("zysrl",zysrl);

        JSONObject ugo = new JSONObject();
        ugo.put("max",paras.getUgoM());
        ugo.put("min",paras.getUgoS());
        ugo.put("rate",paras.getUgo());
        xajpara.put("ugo",ugo);

        JSONObject ogf = new JSONObject();
        ogf.put("max",paras.getOgfM());
        ogf.put("min",paras.getOgfS());
        ogf.put("rate",paras.getOgf());
        xajpara.put("ogf",ogf);

        JSONObject rcfs = new JSONObject();
        rcfs.put("max",paras.getRcfsM());
        rcfs.put("min",paras.getRcfsS());
        rcfs.put("rate",paras.getRcfs());
        xajpara.put("rcfs",rcfs);

        JSONObject rcfr = new JSONObject();
        rcfr.put("max",paras.getRcfrM());
        rcfr.put("min",paras.getRcfrS());
        rcfr.put("rate",paras.getRcfr());
        xajpara.put("rcfr",rcfr);

        JSONObject ctw = new JSONObject();
        ctw.put("max",paras.getCtwM());
        ctw.put("min",paras.getCtwS());
        ctw.put("rate",paras.getCtw());
        xajpara.put("ctw",ctw);

        JSONObject uctw = new JSONObject();
        uctw.put("max",paras.getUctwM());
        uctw.put("min",paras.getUctwS());
        uctw.put("rate",paras.getUctw());
        xajpara.put("uctw",uctw);

        JSONObject cltw = new JSONObject();
        cltw.put("max",paras.getCltwM());
        cltw.put("min",paras.getCltwS());
        cltw.put("rate",paras.getCltw());
        xajpara.put("cltw",cltw);

        JSONObject dec = new JSONObject();
        dec.put("max",paras.getDecM());
        dec.put("min",paras.getDecS());
        dec.put("rate",paras.getDec());
        xajpara.put("dec",dec);

        JSONObject dcsc = new JSONObject();
        dcsc.put("max",paras.getDcscM());
        dcsc.put("min",paras.getDcscS());
        dcsc.put("rate",paras.getDcsc());
        xajpara.put("dcsc",dcsc);

        JSONObject fcdc = new JSONObject();
        fcdc.put("max",paras.getFcdcM());
        fcdc.put("min",paras.getFcdcS());
        fcdc.put("rate",paras.getFcdc());
        xajpara.put("fcdc",fcdc);

        JSONObject pia = new JSONObject();
        pia.put("max",paras.getPiaM());
        pia.put("min",paras.getPiaS());
        pia.put("rate",paras.getPia());
        xajpara.put("pia",pia);

        jsonObject.put("xajpara", xajpara);

        JSONObject psparms = new JSONObject();
        psparms.put("nunms",bisModelPsparms.getNunms());
        psparms.put("ilf",bisModelPsparms.getIlf());
        psparms.put("iw",bisModelPsparms.getIw());
        psparms.put("iwdr",bisModelPsparms.getIwdr());
        psparms.put("nop",bisModelPsparms.getNop());
        psparms.put("glf",bisModelPsparms.getGlf());
        psparms.put("mni",bisModelPsparms.getMni());

        jsonObject.put("psparms",psparms);

        JSONArray areainfo = new JSONArray();

        for(BisXajmodelArearate xa : bisXajmodelArearate){
            JSONObject area = new JSONObject();
            area.put("id",xa.getNum());
            area.put("stcd",xa.getStcdP());
            area.put("name",xa.getStcdPn());
            area.put("areas",xa.getAreas());
            area.put("rate",xa.getRate());
            area.put("lhcsd",xa.getLhcsd());
            area.put("lhcs",xa.getLhcs());
            areainfo.add(area);
        }
        jsonObject.put("areainfo",areainfo);

        if(type==1) {

            JSONArray rains = new JSONArray();
            List<String> dataList = DateIntervalCalculator.calculateDateTimesInInterval(project.getPstartTime(), project.getPendTime());

            for (String str : dataList) {
                JSONObject rain = new JSONObject();
                rain.put("time", str);
                rain.put("stcd",project.getStcdR());
                StRiverR stRiverR = stRiverRService.queryByTMAndStcd(str, project.getStcdR());
                if (ObjectUtils.allNotNull(stRiverR)) {
                    rain.put("mq", stRiverR.getQ());
                } else {
                    rain.put("mq", "0");
                }

                BisReferencedData bisReferencedData = bisReferencedDataService.getRandomData();
                rain.put("erate", bisReferencedData.getZfxl());


                JSONArray stcdinfo = new JSONArray();


                List<String> stcdpList = bisXajmodelArearate.stream()
                        .map(BisXajmodelArearate::getStcdP)
                        .collect(Collectors.toList());
                for (String stcdp : stcdpList) {
                    List<StPptnR> stPptnRList = stPptnRMService.queryAllStPptn(str, stcdp);
                    if(stPptnRList.size()>0){
                        for (StPptnR stp : stPptnRList) {
                            JSONObject stcd_info = new JSONObject();
                            stcd_info.put("stcd", stp.getStcd());
                            stcd_info.put("drp", stp.getDrp());
                            stcdinfo.add(stcd_info);
                        }
                        rain.put("stcdinfo", stcdinfo);
                    }else{
                        JSONObject stcd_info = new JSONObject();
                        stcd_info.put("stcd", stcdp);
                        stcd_info.put("drp", 0.0);
                        stcdinfo.add(stcd_info);
                        rain.put("stcdinfo", stcdinfo);
                    }

                }

                rains.add(rain);
            }
            jsonObject.put("rains", rains);
        }else{
            project.setPstartTime(DateIntervalCalculator.stringToDate(dataObjectList.get(0).getTime()));
            project.setPendTime(DateIntervalCalculator.stringToDate(dataObjectList.get(dataObjectList.size()-1).getTime()));
            jsonObject.put("rains",JSONArray.parseArray(JSONArray.toJSONString(dataObjectList)));
        }
        return jsonObject;
    }
}
